﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SCG.WinForms;
using SCG.SolarVengeanceEngine;
using SCG.General;
using SCG.SolarVengeanceEngine.StarShips;

namespace SCG.SolarVengeance
{
    public partial class BuildStarShipPanel : BasePanel
    {
        //constructors
        public BuildStarShipPanel()
            : base()
        {
            InitializeComponent();
        }

        //which state is this interface in?
        private BuildMode _buildMode;
        public BuildMode BuildMode
        {
            get
            {
                return _buildMode;
            }
            set
            {
                _buildMode = value;
                switch (_buildMode)
                {
                    case BuildMode.BuildFromStarShip:
                    case BuildMode.BuildFromStarSystem:
                        lblBuild.Text = "Build StarShip";
                        pnlButtons.Visible = true;
                        pnlAutoBuild.Visible = false;
                        break;
                    default:
                        lblBuild.Text = "Set AutoBuild Type";
                        pnlButtons.Visible = false;
                        pnlAutoBuild.Visible = true;
                        lvShipType.SynchronizeStarShips(Game.CurrentPlayer.ShipTypesAvailable);
                        ShipTypeDetails = GamePage.SystemSelected.AutoStarShipType;
                        break;
                }
            }
        }

        //set up ship list
        public override void Initialize()
        {
            lvShipType.Color = Game.CurrentPlayer.Color.ToColor();
        }

        //set up the interface to reflect a starship type
        public StarShipDescriptor ShipTypeDetails
        {
            get
            {
                StarShipDescriptor sd = new StarShipDescriptor(SelectedStarShipType, spinEngines.Value, spinPrimary.Value, cbCloak.Checked);
                return sd;
            }
            set
            {
                lvShipType.SelectStarShipType(value.ShipType);
                spinEngines.Value = value.Engines;
                spinPrimary.Value = value.Value;
                cbCloak.Checked = value.Cloaked;
            }
        }

        //update info every impulse
        public override void ImpulseUpdate()
        {
            lvShipType.SynchronizeStarShips(Game.CurrentPlayer.ShipTypesAvailable);
            if (lvShipType.SelectedItems.Count == 0)
                if (lvShipType.Items.Count > 0)
                    lvShipType.Items[0].Selected = true;

            UpdateCost();
            Refresh();
        }

        //remember the last selected starship type
        public StarShipType SelectedStarShipType { get; set; }

        //keep interface snappy
        private void lvShipType_MouseUp(object sender, MouseEventArgs e)
        {
            lvShipType.Refresh();
        }

        //selected a ship type
        private bool _avoidSettingFavorite = false;
        private void lvShipType_StarShipTypeSelected(object sender, StarShipTypeEventArgs e)
        {
            SelectedStarShipType = lvShipType.SelectedStarShipType;
            if (BuildMode != BuildMode.SetAutoBuildStarShip)
                lblBuild.Text = "Build " + SelectedStarShipType;

            //primary system
            if (SelectedStarShipType.GetPrimarySystemName() != "")
            {
                lblPrimarySystem.Text = SelectedStarShipType.GetPrimarySystemName();
                lblPrimarySystem.Visible = true;
                spinPrimary.Visible = true;
            }
            else
            {
                lblPrimarySystem.Visible = false;
                spinPrimary.Visible = false;
            }

            //fixed engines?
            lblEngines.Visible = SelectedStarShipType.GetFixedEngines() == 0;
            spinEngines.Visible = lblEngines.Visible;

            //revert to the favorite settings for this ship type
            StarShip favorite = GetFavoriteSettings(SelectedStarShipType);
            _avoidSettingFavorite = true;
            spinEngines.Value = favorite.Engines;
            spinPrimary.Value = favorite.Value;
            _avoidSettingFavorite = false;

            UpdateCost();
            Refresh();
        }

        //return available resources
        private int AvailableResources
        {
            get
            {
                if (BuildMode != BuildMode.BuildFromStarShip)
                    return GamePage.SystemSelected.ResourcesInt;
                else
                {
                    ResourceStarShip builder = GamePage.ShipsSelected.Builder;
                    if (builder != null)
                        return builder.ResourcesInt;
                    else
                        return 0;
                }
            }
        }

        //return the StarSystem being built from
        private StarSystem BuildSystem
        {
            get
            {
                if (BuildMode == BuildMode.BuildFromStarSystem)
                    return GamePage.SystemSelected;
                else
                    return null;
            }
        }

        //update cost
        private void UpdateCost()
        {
            int cost = ShipCostCalculator.GetCost(SelectedStarShipType, spinEngines.Value, spinPrimary.Value, cbCloak.Checked, BuildSystem);
            lblCostValue.Text = cost.ToString("N0");

            //update appropriate interface
            if (BuildMode == BuildMode.SetAutoBuildStarShip)
            {
                lblCostValue.ForeColor = Color.White;
            }
            else
            {
                //enough resources?
                if (cost <= AvailableResources)
                {
                    //yes, selectively enable arrow buttons
                    lblCostValue.ForeColor = Color.Lime;
                    foreach (Control ctl in pnlButtons.Controls)
                        if (ctl.Tag != null)
                        {
                            SCGPoint pt = GetEncodedPoint(ctl);
                            if (Game.GetObjectAt(pt.X, pt.Y) == null)
                                ctl.Visible = true;
                            else
                                ctl.Visible = false;
                            ctl.Refresh();
                        }
                }
                else
                {
                    //no, disable everything
                    lblCostValue.ForeColor = Color.Red;
                    foreach (Control ctl in pnlButtons.Controls)
                    {
                        if (ctl.Tag != null)
                        {
                            ctl.Visible = false;
                            ctl.Refresh();
                        }
                    }
                }
            }
            lblCostValue.Refresh();
        }

        //values changing
        private void spinEngines_ValueChanged(object sender, EventArgs e)
        {
            ValuesChanged();
        }

        private void ValuesChanged()
        {
            UpdateCost();
            if (!_avoidSettingFavorite)
            {
                StarShip dummy = GetFavoriteSettings(SelectedStarShipType);
                dummy.Engines = spinEngines.Value;
                dummy.Value = spinPrimary.Value;
            }
        }

        //get max value possible
        private void spinPrimary_MaxValueRequested(object sender, EventArgs e)
        {
            int value = 2;
            while (ShipCostCalculator.GetCost(SelectedStarShipType, spinEngines.Value, value, cbCloak.Checked, BuildSystem) <= AvailableResources)
                value++;
            spinPrimary.Value = value - 1;
            spinPrimary.Refresh();
        }

        //get max engines possible
        private void spinEngines_MaxValueRequested(object sender, EventArgs e)
        {
            int engines = 2;
            while (ShipCostCalculator.GetCost(SelectedStarShipType, engines, spinPrimary.Value, cbCloak.Checked, BuildSystem) <= AvailableResources && engines <= 20)
                engines++;
            spinEngines.Value = engines - 1;
            spinEngines.Refresh();
        }

        //build!
        private void btnR_Click(object sender, EventArgs e)
        {
            Control ctl = sender as Control;
            SCGPoint pt = GetEncodedPoint(ctl);
            ctl.Visible = false;
            if (BuildMode == BuildMode.BuildFromStarSystem)
                GamePage.SubmitOrder(OrderType.BuildStarShip, GamePage.SystemSelected, pt.X, pt.Y, SelectedStarShipType, spinEngines.Value, spinPrimary.Value, cbCloak.Checked);
            else
            {
                ResourceStarShip builder = GamePage.ShipsSelected.Builder;
                if (builder != null)
                    GamePage.SubmitOrder(OrderType.ShipBuildStarShip, builder, pt.X, pt.Y, SelectedStarShipType, spinEngines.Value, spinPrimary.Value, cbCloak.Checked);
            }
        }

        //get encoded direction
        private SCGPoint GetEncodedPoint(Control ctl)
        {
            SCGPoint pt = new SCGPoint();
            string dir = ctl.Tag as string;
            string[] tokens = dir.Split(',');
            pt.X = Int32.Parse(tokens[0]);
            pt.Y = Int32.Parse(tokens[1]);
            SVMapObject svm;
            if (BuildMode == BuildMode.BuildFromStarSystem)
                svm = GamePage.SystemSelected;
            else
                svm = GamePage.ShipsSelected.Builder;
            pt.Offset(svm.Location);
            return pt;
        }

        //get favorite settings for specific ship type
        public StarShip GetFavoriteSettings(StarShipType st)
        {
            if (FavoriteSettings.ContainsKey(st))
                return FavoriteSettings[st];
            else
            {
                StarShip dummy = StarShip.CreateInstance(null, null, st, 8, 4, null);
                FavoriteSettings[st] = dummy;
                return dummy;
            }
        }

        //private members
        private static Dictionary<StarShipType, StarShip> FavoriteSettings = new Dictionary<StarShipType, StarShip>();

        //load arrow images
        private void BuildStarShipPanel_Load(object sender, EventArgs e)
        {
            Image arrow = Bitmap.FromFile("Images\\Arrow.bmp");
            btnU.Image = arrow;
            arrow = ImageUtils.RotateImage(arrow, 45);
            btnUR.Image = arrow;
            arrow = ImageUtils.RotateImage(arrow, 45);
            btnR.Image = arrow;
            arrow = ImageUtils.RotateImage(arrow, 45);
            btnDR.Image = arrow;
            arrow = ImageUtils.RotateImage(arrow, 45);
            btnD.Image = arrow;
            arrow = ImageUtils.RotateImage(arrow, 45);
            btnDL.Image = arrow;
            arrow = ImageUtils.RotateImage(arrow, 45);
            btnL.Image = arrow;
            arrow = ImageUtils.RotateImage(arrow, 45);
            btnUL.Image = arrow;
        }

        //cancel build mode
        private void btnCancelBuild_Click(object sender, EventArgs e)
        {
            GamePage.SidePanelMode = BuildMode == BuildMode.BuildFromStarSystem ? SidePanels.StarSystem : SidePanels.StarShip;
        }

        //cancel auto starship mode
        private void btnCancelAuto_Click(object sender, EventArgs e)
        {
            GamePage.SidePanelMode = SidePanels.StarSystem;
        }

        //set the autotype mode
        private void btnSetAutoType_Click(object sender, EventArgs e)
        {
            GamePage.SubmitOrder(OrderType.SetAutoBuildType, GamePage.SystemSelected, ShipTypeDetails);
            GamePage.SubmitOrder(OrderType.AutoStarShip, GamePage.SystemSelected, true);
            GamePage.SidePanelMode = SidePanels.StarSystem;
        }

        //cloaking on/off
        private void cbCloak_CheckedChanged(object sender, EventArgs e)
        {
            if (cbCloak.Checked)
                MainForm.PlaySound("CheckOn");
            else
                MainForm.PlaySound("CheckOff");
            ValuesChanged();
        }
    }

    //determines the state of the build starship interface
    public enum BuildMode { BuildFromStarSystem, BuildFromStarShip, SetAutoBuildStarShip };
}
